#pragma once
#include <iostream>
#include <cassert>
using namespace std;
#define SIZE (64 * 1024)
#define PAGE_SIZE 11



class Block
{
public:
	Block():_blocksize(0), _mem(nullptr), _ptr(nullptr), _count(0)
	{}

	void Init(size_t size)
	{
		_blocksize = size;
		_count = SIZE / _blocksize;

		_mem = new char[SIZE];
		_ptr = _mem;

		char* ptr = _ptr;
		for (int i = 0; i < SIZE / (int)_blocksize - 1; i++)
		{
			*(char**)ptr = ptr + _blocksize;
			ptr += _blocksize;
		}
		*(char**)ptr = nullptr;
	}

	void* FLlloc(size_t size)
	{
		if (size > _blocksize || _count <= 0) return nullptr;

		char* ret = _ptr;
		_ptr = *(char**)_ptr;
		_count--;
		cout << "mallco: " << (void*)ret << endl;
		return ret;
	}

	void FLfree(void* ptr)
	{
		assert(ptr != nullptr \
		/* && (int)ptr >= (int)_mem && (int)ptr <= (int)((int)_mem + SIZE - _blocksize)*/);
		cout << "free: " << (void*)ptr << endl;
		*(char**)ptr = _ptr;
		_ptr = (char*)ptr;
		_count++;
	}

	void* GetMem()
	{
		return _mem;
	}

	~Block()
	{
		delete[] _mem;
	}
private:
	size_t _blocksize;
	char* _mem;
	char* _ptr;
	size_t _count;
};

class MemoryPool
{
private:
	int Pow(int x, int y)
	{
		int sum = 1;
		while (y)
		{
			sum *= x;
			y--;
		}
		return sum;
	}

	int RetIndex(void* ptr)
	{
		for (int i = 0; i < PAGE_SIZE; i++)
		{
			if ((int)ptr >= (int)(_pages[i].GetMem())
				&& (int)ptr < (int)(_pages[i].GetMem()) + SIZE)
				return i;
		}
		return -1;
	}
public:
	MemoryPool()
	{
		for (int i = 0; i < PAGE_SIZE; i++)
		{
			_pages[i].Init(Pow(2, i + 5));
		}

		_mem = (void*)&_pages[0];
	}

	void* FLlloc(size_t size)
	{
		if (size > SIZE && size == 0) return nullptr;

		if (size <= 32)
			return _pages[0].FLlloc(size);

		int n = 0;
		while (size > 0)
		{
			size /= 2;
			n++;
		}

		return _pages[n - 5].FLlloc(size);
	}

	void FLfree(void* ptr)
	{
		assert(ptr != nullptr);
		//int index = (int)((char*)ptr - (char*)_mem) / SIZE;
		int index = RetIndex(ptr);
		assert(index != -1);

		_pages[index].FLfree(ptr);
	}

	~MemoryPool()
	{}
private:
	Block _pages[PAGE_SIZE];
	void* _mem;
};